package com.spring;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class DyApplicationContext {

    private Class configClass;
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private List<BeanPostProcessor> beanPostProcessorList = new LinkedList<>();

    public DyApplicationContext(Class configClass) {
        this.configClass = configClass;

        scan(configClass);

        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {

            String beanName = beanDefinitionEntry.getKey();
            BeanDefinition beanDefinition = beanDefinitionEntry.getValue();

            if (beanDefinition.getScope().equals("singleton")) {
                try {
                    Object bean = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, bean);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                //原型
            }
        }

    }


    private Object createBean(String beanName, BeanDefinition beanDefinition) throws Exception {
        Class clazz = beanDefinition.getType();
        Constructor constructor = clazz.getConstructor();
        Object bean = constructor.newInstance();

        //依赖注入
        for (Field field : clazz.getDeclaredFields()) {

            if (field.isAnnotationPresent(AutoWried.class)) {
                field.setAccessible(true);
                field.set(bean, getBean(field.getName()));
            }
        }

        if (bean instanceof BeanNameAware){
            BeanNameAware beanNameAware = (BeanNameAware) bean;
            beanNameAware.setBeanName(beanName);
        }

        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            beanPostProcessor.postProcessBeforeInitialization(bean,beanName);
        }

        //执行初始化
        if (bean instanceof InitializingBean) {
            InitializingBean initializingBean = (InitializingBean) bean;
            initializingBean.afterPropertiesSet();
        }

        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
        }

        return bean;
    }


    private void scan(Class configClass) {
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String basePackages = componentScan.value();
            String path = basePackages.replace(".", "/");
            System.out.println(path);

            //定位
            ClassLoader classLoader = DyApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);
            File file = new File(resource.getFile());

            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File f : files) {
                    String absolutePath = f.getAbsolutePath();

                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\", ".");
                    System.out.println(absolutePath);
                    try {
                        //加载
                        Class<?> clazz = classLoader.loadClass(absolutePath);
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(clazz);
                        if (clazz.isAnnotationPresent(Commonent.class)) {

                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }

                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scope = clazz.getAnnotation(Scope.class);
                                String value = scope.value();
                                //判断单例还是 原型
                                beanDefinition.setScope(value);

                            } else {
                                //单例
                                beanDefinition.setScope("singleton");
                            }
                            Commonent commonent = clazz.getAnnotation(Commonent.class);
                            String beanName = Objects.equals(commonent.value(), "") ? Introspector.decapitalize(clazz.getSimpleName()) : commonent.value();
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    } catch (Exception e) {
                    }
                }
            }
        }
    }

    public Object getBean(String beanName) throws Exception {
        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new NullPointerException();
        }
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        String scope = beanDefinition.getScope();

        //判断单例还是原型
        if (scope.equals("singleton")) {
            Object singleton = singletonObjects.get(beanName);
            if (singleton == null) {
                singletonObjects.put(beanName, createBean(beanName, beanDefinition));
            }
            return singleton;
        } else {
            //原型
            return createBean(beanName, beanDefinition);
        }

    }


    public <T> T getBean(Class<T> type) {
        return null;
    }


}
